package com.xiaoka.flutter_plugin_gdmap;

import android.Manifest;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Build;
import android.text.TextUtils;
import android.util.Log;
import android.widget.Toast;

import androidx.annotation.NonNull;
import androidx.core.content.ContextCompat;

import com.amap.api.location.AMapLocation;
import com.amap.api.location.AMapLocationClient;
import com.amap.api.location.AMapLocationClientOption;
import com.amap.api.location.AMapLocationListener;
import com.amap.api.maps.AMapUtils;
import com.amap.api.maps.model.LatLng;
import com.amap.api.services.core.LatLonPoint;
import com.amap.api.services.core.PoiItem;
import com.amap.api.services.core.ServiceSettings;
import com.amap.api.services.poisearch.PoiResult;
import com.amap.api.services.poisearch.PoiSearch;
import com.amap.api.services.route.DistanceResult;
import com.amap.api.services.route.DistanceSearch;
import com.google.gson.Gson;
import com.xiaoka.flutter_plugin_gdmap.AMap.AMapPluginFactory;
import com.xiaoka.flutter_plugin_gdmap.AMapNavi.AMapNaviPluginFactory;
import com.xiaoka.flutter_plugin_gdmap.AMapPolygon.AMapPolygonPluginFactory;
import com.xiaoka.flutter_plugin_gdmap.poi.AddressSearchBean;

import java.util.ArrayList;
import java.util.List;

import io.flutter.embedding.engine.plugins.FlutterPlugin;
import io.flutter.embedding.engine.plugins.activity.ActivityAware;
import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding;
import io.flutter.plugin.common.EventChannel;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugin.common.MethodChannel.Result;

/**
 * FlutterPluginGdmapPlugin
 */
public class FlutterPluginGdmapPlugin implements FlutterPlugin, ActivityAware, MethodChannel.MethodCallHandler {

    private Context context;
    private Activity activity;
    private MethodChannel channel;
    private EventChannel eventChannel;
    private EventChannel.EventSink mEventSink;

    private EventChannel poiEventChannel;
    private EventChannel.EventSink poiEventSink;

    private EventChannel distanceEventChannel;
    private EventChannel.EventSink distanceEventSink;

    private FlutterPluginBinding mFlutterPluginBinding;

    //定位信息
    private String mLocation = "";
    //声明AMapLocationClient类对象
    public AMapLocationClient mLocationClient = null;
    //声明AMapLocationClientOption对象
    public AMapLocationClientOption option = null;

    Intent mForegroundService;//前台服务

    LocationBean locationBean;//当前定位数据类

    //声明定位回调监听器
    public AMapLocationListener mLocationListener = new AMapLocationListener() {
        @Override
        public void onLocationChanged(AMapLocation aMapLocation) {
            if (aMapLocation != null) {
                if (aMapLocation.getErrorCode() == 0) {
                    mLocation = getLocationInfoMap(aMapLocation);
                } else {
                    mLocation = "";
                    Log.e("定位~~~~~~~~~~", "定位获取错误, ErrCode:" + aMapLocation.getErrorCode() + ", errInfo:" + aMapLocation.getErrorInfo());
                }
                if (mEventSink != null) {
                    mEventSink.success(mLocation);
                }
            }
        }
    };

    @Override
    public void onAttachedToEngine(@NonNull FlutterPluginBinding flutterPluginBinding) {
        context = flutterPluginBinding.getApplicationContext();
        mFlutterPluginBinding = flutterPluginBinding;

        channel = new MethodChannel(flutterPluginBinding.getBinaryMessenger(), Constant.AMAP_CHANNEL_NAME + "/location");
        eventChannel = new EventChannel(flutterPluginBinding.getBinaryMessenger(), Constant.AMAP_CHANNEL_NAME + "/locationChanged");
        poiEventChannel = new EventChannel(flutterPluginBinding.getBinaryMessenger(), Constant.AMAP_CHANNEL_NAME + "/getPoiList");
        distanceEventChannel = new EventChannel(flutterPluginBinding.getBinaryMessenger(), Constant.AMAP_CHANNEL_NAME + "/getDistance");
        channel.setMethodCallHandler(this);
        eventChannel.setStreamHandler(new EventChannel.StreamHandler() {
            @Override
            public void onListen(Object arguments, EventChannel.EventSink events) {
                mEventSink = events;
            }

            @Override
            public void onCancel(Object arguments) {

            }
        });
        poiEventChannel.setStreamHandler(new EventChannel.StreamHandler() {
            @Override
            public void onListen(Object arguments, EventChannel.EventSink events) {
                poiEventSink = events;
            }

            @Override
            public void onCancel(Object arguments) {

            }
        });
        distanceEventChannel.setStreamHandler(new EventChannel.StreamHandler() {
            @Override
            public void onListen(Object arguments, EventChannel.EventSink events) {
                distanceEventSink = events;
            }

            @Override
            public void onCancel(Object arguments) {

            }
        });
        if (!LittleUtils.isOPenGPS(context)) {
            Toast.makeText(context, "定位服务没有开启，请在设置中打开定位服务开关", Toast.LENGTH_SHORT).show();
        }
    }

    /**
     * 初始化
     *
     * @param flutterPluginBinding
     */
    public void init(Context context) {
        try {
            //初始化定位
            mLocationClient = new AMapLocationClient(context);
        } catch (Exception e) {
            e.printStackTrace();
        }
        //设置定位回调监听
        mLocationClient.setLocationListener(mLocationListener);

        //初始化AMapLocationClientOption对象
        option = new AMapLocationClientOption();
        //设置定位场景-出行，目前支持三种场景（签到、出行、运动，默认无场景）
        option.setLocationPurpose(AMapLocationClientOption.AMapLocationPurpose.Transport);
        //设置定位模式为AMapLocationMode.Hight_Accuracy，高精度模式。
        option.setLocationMode(AMapLocationClientOption.AMapLocationMode.Hight_Accuracy);
        //设置定位间隔,单位毫秒,默认为2000ms，最低1000ms。
        option.setInterval(5000);
        //设置是否返回地址信息（默认返回地址信息）
        option.setNeedAddress(true);
        if (null != mLocationClient) {
            mLocationClient.setLocationOption(option);
            //设置场景模式后最好调用一次stop，再调用start以保证场景模式生效
            mLocationClient.stopLocation();
            mLocationClient.startLocation();
        }
    }

    @Override
    public void onMethodCall(@NonNull MethodCall call, @NonNull Result result) {
        Log.e("定位~~~~~~~~~~", "插件接收到通信Method:" + call.method);
        if (call.method.equals("privacy")) {
            ServiceSettings.updatePrivacyShow(context, true, true);
            ServiceSettings.updatePrivacyAgree(context, true);
        } else if (call.method.equals("initGdMap")) {
            init(context);
        } else if (call.method.equals("setKey")) {
            //设置高德key
            result.success("android端需要在Manifest里配置key");
        } else if (call.method.equals("inspectionGPS")) {
            checkPermission();
            //检查GPS开启状态
            if (LittleUtils.isOPenGPS(context)) {
                result.success(true);
            } else {
                result.success(false);
            }
        } else if (call.method.equals("startLocation")) {
            checkPermission();
            //启动定位
            mLocationClient.startLocation();
        } else if (call.method.equals("stopLocation")) {
            //停止定位
            mLocationClient.stopLocation();
        } else if (call.method.equals("getLocation")) {
            checkPermission();
            //单次获取最新的定位数据
            result.success(mLocation);
        } else if (call.method.equals("startService")) {
            //启动前台服务
            startService();
        } else if (call.method.equals("stopService")) {
            //关闭前台服务
            stopService();
        } else if (call.method.equals("locationSearch")) {
            checkPermission();
            //位置搜索
            getLocationSearch(call.argument("address").toString(), Integer.parseInt(call.argument("page").toString()));
        } else if (call.method.equals("distanceSearch")) {
            //行车距离计算
            getDistanceSearch(new Gson().fromJson(call.argument("startLocation").toString(), LatLng.class), new Gson().fromJson(call.argument("endLocation").toString(), LatLng.class));
        } else if (call.method.equals("distanceCompute")) {
            //两点间直线距离计算
            LatLng startLatLng = new Gson().fromJson(call.argument("startLocation").toString(), LatLng.class);
            LatLng endLatLng = new Gson().fromJson(call.argument("endLocation").toString(), LatLng.class);
            float distance = AMapUtils.calculateLineDistance(startLatLng, endLatLng);
            result.success(distance + "");
        } else {
            result.notImplemented();
        }
    }

    public void checkPermission() {
        if (activity != null) {
            LittleUtils.getPermission(activity);
        }
        //判断是否授予应用定位权限
        if (ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            Toast.makeText(context, "请授予应用定位权限再使用该功能", Toast.LENGTH_SHORT).show();
            LittleUtils.getPermission(activity);
        }
    }

    /**
     * 启动前台服务
     */
    public void startService() {
        if (!ForegroundService.serviceIsLive) {
            // Android 8.0使用startForegroundService在前台启动新服务
            mForegroundService = new Intent(activity, ForegroundService.class);
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                activity.startForegroundService(mForegroundService);
            } else {
                activity.startService(mForegroundService);
            }
        }
    }

    /**
     * 关闭前台服务
     */
    public void stopService() {
        mForegroundService = new Intent(activity, ForegroundService.class);
        activity.stopService(mForegroundService);
    }

    @Override
    public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) {
        channel.setMethodCallHandler(null);
        eventChannel.setStreamHandler(null);
    }

    @Override
    public void onAttachedToActivity(@NonNull ActivityPluginBinding binding) {
        this.activity = binding.getActivity();
//        LittleUtils.getPermission(activity);
        //地图
        mFlutterPluginBinding.getPlatformViewRegistry().registerViewFactory(Constant.AMAP_CHANNEL_NAME + "/AMapView", new AMapPluginFactory(mFlutterPluginBinding.getBinaryMessenger(), activity));
        //地图围栏
        mFlutterPluginBinding.getPlatformViewRegistry().registerViewFactory(Constant.AMAP_CHANNEL_NAME + "/AMapPolygonView", new AMapPolygonPluginFactory(mFlutterPluginBinding.getBinaryMessenger(), activity));
        //导航
        mFlutterPluginBinding.getPlatformViewRegistry().registerViewFactory(Constant.AMAP_CHANNEL_NAME + "/AMapNaviView", new AMapNaviPluginFactory(mFlutterPluginBinding.getBinaryMessenger(), activity));
    }

    @Override
    public void onDetachedFromActivityForConfigChanges() {

    }

    @Override
    public void onReattachedToActivityForConfigChanges(@NonNull ActivityPluginBinding binding) {

    }

    @Override
    public void onDetachedFromActivity() {

    }

    /**
     * 定位数据转换
     *
     * @param amapLocation
     * @return
     */
    private String getLocationInfoMap(AMapLocation amapLocation) {
        locationBean = new LocationBean();
        locationBean.setLongitude(amapLocation.getLongitude());
        locationBean.setLatitude(amapLocation.getLatitude());
        locationBean.setAltitude(amapLocation.getAltitude());
        locationBean.setAccuracy(amapLocation.getAccuracy());
        locationBean.setBearing(amapLocation.getBearing());
        locationBean.setSpeed(amapLocation.getSpeed());
        locationBean.setLocationType(amapLocation.getLocationType());
        locationBean.setCountry(amapLocation.getCountry());
        locationBean.setProvince(amapLocation.getProvince());
        locationBean.setCity(amapLocation.getCity());
        locationBean.setDistrict(amapLocation.getDistrict());
        locationBean.setStreet(amapLocation.getStreet());
        locationBean.setCityCode(amapLocation.getCityCode());
        locationBean.setAdCode(amapLocation.getAdCode());
        locationBean.setAoiName(amapLocation.getAoiName());
        locationBean.setAddress(amapLocation.getAddress());
        locationBean.setTime(amapLocation.getTime());
        return new Gson().toJson(locationBean);
    }

    /**
     * 位置搜索
     */
    private void getLocationSearch(String address, int page) {
        Log.e("位置搜索~~~~~~", "位置搜索:" + address);
        if (locationBean == null) {
            return;
        }
        String deepType = "汽车服务|汽车销售|汽车维修|摩托车服务|餐饮服务|购物服务|生活服务|体育休闲服务|医疗保健服务|住宿服务|风景名胜|商务住宅|政府机构及社会团体|科教文化服务|交通设施服务|金融保险服务|公司企业|道路附属设施|地名地址信息|公共设施|通行设施";
//        String deepType="";
        PoiSearch.Query query = new PoiSearch.Query(address, deepType, locationBean.getCityCode());
        //keyWord表示搜索字符串，
        //第二个参数表示POI搜索类型，二者选填其一，选用POI搜索类型时建议填写类型代码，码表可以参考下方（而非文字）
        //cityCode表示POI搜索区域，可以是城市编码也可以是城市名称，也可以传空字符串，空字符串代表全国在全国范围内进行搜索
        query.setPageSize(20);// 设置每页最多返回多少条poiitem
        query.setPageNum(page);//设置查询页码
//        query.setDistanceSort(true);//设置是否按距离排序
//        query.setLocation(new LatLonPoint(locationBean.getLatitude(), locationBean.getLongitude()));//设置搜索中心经纬度
        PoiSearch poiSearch = null;
        try {
            poiSearch = new PoiSearch(context, query);
        } catch (Exception e) {
            e.printStackTrace();
        }
        if (TextUtils.isEmpty(address)) {
            poiSearch.setBound(new PoiSearch.SearchBound(new LatLonPoint(locationBean.getLatitude(), locationBean.getLongitude()), 10000));//设置周边搜索的中心点以及半径
        }
        poiSearch.setOnPoiSearchListener(new PoiSearch.OnPoiSearchListener() {
            @Override
            public void onPoiSearched(PoiResult poiResult, int i) {
                if (i == 1000) {
                    ArrayList<PoiItem> pois = poiResult.getPois();
                    List<AddressSearchBean> list = new ArrayList<>();
                    for (PoiItem poi : pois) {
                        AddressSearchBean bean = new AddressSearchBean();
                        bean.setName(poi.getTitle());
                        bean.setAddress(poi.getSnippet());
                        bean.setDistance(poi.getDistance());
                        bean.setCity(poi.getCityName());
                        bean.setLatitude(poi.getLatLonPoint().getLatitude());
                        bean.setLongitude(poi.getLatLonPoint().getLongitude());
                        list.add(bean);
                    }
                    if (poiEventSink != null) {
                        poiEventSink.success(new Gson().toJson(list));
                    }
                } else {
                    poiEventSink.success("");
                }
            }

            @Override
            public void onPoiItemSearched(PoiItem poiItem, int i) {

            }
        });
        poiSearch.searchPOIAsyn();
    }

    /**
     * 距离搜索
     */
    private void getDistanceSearch(LatLng startLatLng, LatLng endLatLng) {
        DistanceSearch distanceSearch = null;
        try {
            distanceSearch = new DistanceSearch(context);
        } catch (Exception e) {
            e.printStackTrace();
        }

        DistanceSearch.DistanceQuery distanceQuery = new DistanceSearch.DistanceQuery();

        //设置起点和终点，其中起点支持多个
        List<LatLonPoint> latLonPoints = new ArrayList<LatLonPoint>();
        latLonPoints.add(new LatLonPoint(startLatLng.latitude, startLatLng.longitude));

        distanceQuery.setOrigins(latLonPoints);
        distanceQuery.setDestination(new LatLonPoint(endLatLng.latitude, endLatLng.longitude));
        //设置测量方式，支持直线和驾车
        distanceQuery.setType(DistanceSearch.TYPE_DRIVING_DISTANCE);
        distanceSearch.setDistanceSearchListener(new DistanceSearch.OnDistanceSearchListener() {
            @Override
            public void onDistanceSearched(DistanceResult distanceResult, int code) {
                if (code == 1000) {
                    //距离米
                    String distance = distanceResult.getDistanceResults().get(0).getDistance() + "";
                    Log.e("~~~~~", "路程距离：" + distance);
                    if (distanceEventSink != null) {
                        distanceEventSink.success(distance);
                    }
                } else {
                    Log.e("~~~~~", "路程距离：查询失败，code:" + code);
                    distanceEventSink.success("0");
                }
            }
        });
        distanceSearch.calculateRouteDistanceAsyn(distanceQuery);
    }

}
